约 2415 字

约 12 分钟

#动态类型与 PSObject

#简介

PowerShell 中的每个对象都会被包装成 PSObject。这层包装让原本的 .NET 对象可以临时附加属性、方法和类型名,而不需要修改原始类型。理解 PSObject 是掌握动态对象、自定义输出和 ETS 的关键。

#PSObject

创建对象后,可以通过 PSObject 属性查看它的成员和类型信息:

$obj = [pscustomobject]@{ Name = 'demo' }

$obj.PSObject.Properties
$obj.PSObject.Methods
$obj.PSObject.Properties['Name'].Value

$obj.PSObject.Properties 返回属性集合,每个元素包含 Name、MemberType、Value 等信息。

#pstypenames

每个对象都有一条类型名链,PowerShell 用它查找类型数据:

$obj = [pscustomobject]@{ Name = 'demo' }
$obj.pstypenames

输出依次为 System.Management.Automation.PSCustomObject 和 System.Object。也可以使用 $obj.PSObject.TypeNames,两者指向同一份类型名集合。向链首插入自定义类型名后,可以针对该类型名配置成员和格式化:

$obj.PSObject.TypeNames.Insert(0, 'My.App.Demo')

#Add-Member

Add-Member 用于向对象实例动态添加成员。默认不输出结果,需要返回对象时使用 -PassThru:

$obj = [pscustomobject]@{ Name = 'demo' }

$obj | Add-Member -MemberType NoteProperty -Name Version -Value '1.0'
$obj | Add-Member -MemberType ScriptProperty -Name Label -Value {
    "$($this.Name) v$($this.Version)"
}
$obj | Add-Member -MemberType ScriptMethod -Name Describe -Value {
    "$($this.Name) version $($this.Version)"
}

$obj.Version
$obj.Label
$obj.Describe()

输出依次为 1.0、demo v1.0 和 demo version 1.0。

NoteProperty 保存静态值;ScriptProperty 和 ScriptMethod 在每次访问时执行脚本块,其中的 $this 指向当前对象。CodeMethod 则绑定 .NET 静态方法,适合高性能场景。

#属性赋值语法

对于 PSCustomObject,可以直接给不存在的属性赋值,PowerShell 会自动添加 NoteProperty:

$obj = [pscustomobject]@{ Name = 'demo' }
$obj.Enabled = $true
$obj.Enabled
True

这种语法只适用于可以扩展的对象;对多数普通 .NET 对象直接赋值不存在的属性会报错。

#动态成员与类型数据

Add-Member 只影响当前对象实例。如果希望某个类型的所有对象都拥有同样的成员,应使用 Update-TypeData:

Update-TypeData -TypeName 'My.App.Demo' `
    -MemberType ScriptProperty `
    -MemberName Display `
    -Value { "$($this.Name)!" } `
    -Force

更多内容参见 Get-Member 帮助手册。

#注意事项

  • 动态成员默认只存在于当前会话和当前对象实例中。
  • ScriptProperty 每次读取都会执行脚本块,避免在其中进行耗时操作。
  • 类型名和动态成员是元数据,不构成安全边界。
  • 对共享对象添加成员时,其他代码也可能看到这些改动。

#推荐阅读

更新: 2026/11/2

作者: planc

创建: 2026/11/2